#include "LeagueManager.h"
#include "UserManager.h"
#include "Utilities.h"
#include "GameSettings.h"
#include "PlayerManager.h"
#include "TeamManager.h"
#include "League.h"
#include "ZStream.h"

ZStream& LeagueManagerSettings::Serialize(ZStream& o_stream)
{
	o_stream.WriteOpenTag("LeagueLayerSettings");

	o_stream.WriteAttribute("LayerNum", m_layerSettings.size());

	for(size_t i = 0; i < m_layerSettings.size(); ++i)
	{
		m_layerSettings[i].Serialize(o_stream);
	}

	o_stream.WriteCloseTag("LeagueLayerSettings");

	return o_stream;
}
ZStream& LeagueManagerSettings::Deserialize(ZStream& i_stream)
{
	m_layerSettings.clear(); //"cagasotto" pattern

	i_stream.SkipLine();

	size_t layerNum = 0;
	i_stream.ReadAttribute(layerNum);

	for(size_t i = 0; i < layerNum; ++i)
	{
		LeagueLayerSettings layerSett;
		
		layerSett.layerIndex = i;
		if(m_layerSettings.empty())
			layerSett.numOfPromoted = 0;
		else
			layerSett.numOfPromoted = m_layerSettings.back().numOfDemotioned;
	
		layerSett.Deserialize(i_stream);

		m_layerSettings.push_back(layerSett);
	}

	i_stream.SkipLine();

	return i_stream;
}

LeagueManager::LeagueManager(ServiceProvider* i_sp)
	: m_maxTurnsOfSeason(0)
	, m_currentTurn(0)
	, m_sp(i_sp)
{
	assert(i_sp);
}

LeagueManager::~LeagueManager()
{
	Clear();
}

void LeagueManager::Initialize(const LeagueManagerSettings& i_settings)
{
	Clear();
	m_settings = i_settings;

	m_currentSeason = m_sp->GetSettings().GetValue("I_STARTING_YEAR").Get<size_t>();

	CheckConsistency(i_settings);

	for (size_t i = 0; i < i_settings.m_layerSettings.size(); ++i)
	{
		LeagueLayer* layer = new LeagueLayer(m_sp);
		layer->Initialize(i_settings.m_layerSettings[i]);

		m_layers.push_back(layer);

		m_maxTurnsOfSeason = (layer->MaxTurnsOfSeason() > m_maxTurnsOfSeason) ? layer->MaxTurnsOfSeason() : m_maxTurnsOfSeason;	
	}

	LeagueVec leagues;
	for (LayerVecCit it = m_layers.begin(); it != m_layers.end(); ++it)
	{
		leagues = (*it)->GetLeagues();
		Utilities::Append(m_allLeagues, leagues);
		if ((*it)->IsVisible()) 
			Utilities::Append(m_allVisibleLeagues, leagues);
	}
	return;
}

size_t LeagueManager::GetNumOfTeams(bool onlyVisible) const
{
	const LeagueVec* leagues;
	if (onlyVisible)
		leagues = &m_allVisibleLeagues;
	else
		leagues = &m_allLeagues;

	LeagueVecCit it = leagues->begin();
	LeagueVecCit end = leagues->end();
	size_t counter = 0;
	for (; it != end; ++it)
		counter += (*it)->GetSettings().numOfTeams;
	return counter;
}

size_t LeagueManager::GetNumOfLayers(bool onlyVisible) const
{
	if(onlyVisible)
	{
		size_t ret = 0;
		for(LMSettingsCIterator cit = m_settings.m_layerSettings.begin(); cit != m_settings.m_layerSettings.end(); ++cit)
		{
			if((*cit).isVisible)
				++ret;
		}
		return ret;
	}
	else
		return m_settings.m_layerSettings.size();
}

void LeagueManager::Update(const bool i_doNotPrompt)
{
	for(LayerVecIt it  = m_layers.begin(); it != m_layers.end(); ++it)
	{
		LeagueLayer& theLayer = *(*it);
		theLayer.Update(i_doNotPrompt);
	}

	++m_currentTurn;
}

void LeagueManager::EndSeasonUpdate(const bool i_doNotPrompt, std::stringstream& o_message)
{
	// compute promotions and demotions
	LayerVecIt it1 = m_layers.begin();
	for(LayerVecIt it2 = m_layers.begin() + 1; it2 != m_layers.end(); ++it1, ++it2)
		(*it1)->PromoteAndDemote(*it2, i_doNotPrompt, o_message);

	// every layer must update himself 
	for(LayerVecIt it = m_layers.begin(); it != m_layers.end(); ++it)
		(*it)->EndSeasonUpdate(i_doNotPrompt, o_message);

	m_sp->GetPlayerMgr().EndSeasonUpdate();
	m_sp->GetTeamMgr().EndSeasonUpdate();

	m_currentTurn = 0;
	++m_currentSeason;
}

void LeagueManager::Clear()
{
	Utilities::DeepClear(m_layers);

	m_allLeagues.clear();
	m_allVisibleLeagues.clear();

	m_currentTurn = 0;
	m_maxTurnsOfSeason = 0;
}

bool LeagueManager::CheckConsistency(const LeagueManagerSettings &i_settings)
{
	// check consistenza retrocessioni
	LMSettingsCIterator it	= i_settings.m_layerSettings.begin();
	LMSettingsCIterator it2	= it + 1;
	LMSettingsCIterator end	= i_settings.m_layerSettings.end();
	assert(it != end && "No settings available!!!");

	for(; it2 != end; ++it, ++it2)
	{
		size_t MCM = Utilities::GetMCM((*it).numOfLeagues, (*it2).numOfLeagues);
		assert(((*it).numOfDemotioned % MCM) == 0 && "numero squadre retrocesse sbagliato!");
	}

	return true;
}

bool LeagueManager::IsEnded() const
{
	for(LeagueVecCit cit= m_allLeagues.begin(); cit!= m_allLeagues.end(); ++cit)
		if(!(*cit)->IsEnded())
			return false;
	return true;
}

size_t LeagueManager::GetSeasonTurns() const
{
	size_t max = 0;
	LayerVecCit it = m_layers.begin();
	LayerVecCit end = m_layers.end();
	
	for (; it != end; ++it)
	{
		if ((*it)->MaxTurnsOfSeason() > max)
			max = (*it)->MaxTurnsOfSeason();
	}

	return max;
}

ZStream& LeagueManager::Serialize(ZStream& o_stream)
{
	o_stream.WriteOpenTag("LeagueManager");

	o_stream.WriteAttribute("CurrentSeason", m_currentSeason);
	o_stream.WriteAttribute("CurrentTurn", m_currentTurn);

	for(size_t i = 0; i < m_allLeagues.size(); ++i)
		m_allLeagues[i]->Serialize(o_stream);

	o_stream.WriteCloseTag("LeagueManager");

	return o_stream;
}

ZStream& LeagueManager::Deserialize(ZStream& i_stream)
{
	i_stream.SkipLine();

	i_stream.ReadAttribute(m_currentSeason);
	i_stream.ReadAttribute(m_currentTurn);

	for(size_t i = 0; i < m_allLeagues.size(); ++i)
		m_allLeagues[i]->Deserialize(i_stream);

	i_stream.SkipLine();

	return i_stream;
}